Научете как да проектирате и изграждате мощни OLAP системи и складове за данни, използвайки Python. Това ръководство покрива всичко от моделиране на данни и ETL до избор на правилните инструменти като Pandas, Dask и DuckDB.
Python за складиране на данни: Изчерпателно ръководство за проектиране на OLAP системи
В днешния свят, управляван от данни, способността за бърз анализ на огромни количества информация не е просто конкурентно предимство; това е необходимост. Бизнеси по целия свят разчитат на стабилни анализи, за да разбират пазарните тенденции, да оптимизират операциите и да вземат стратегически решения. В основата на тази аналитична способност стоят две основни концепции: Склад за данни (DWH) и системи за онлайн аналитична обработка (OLAP).
Традиционно изграждането на тези системи изискваше специализиран, често собственически и скъп софтуер. Въпреки това, възходът на технологиите с отворен код демократизира инженеринга на данни. Водещ в тази насока е Python, гъвкав и мощен език с богата екосистема, която го прави изключителен избор за изграждане на цялостни решения за данни. Това ръководство предоставя изчерпателен преглед на проектирането и внедряването на системи за складиране на данни и OLAP, използвайки Python стека, пригодено за глобална аудитория от инженери на данни, архитекти и разработчици.
Част 1: Крайъгълните камъни на бизнес интелигентността - DWH и OLAP
Преди да навлезем в Python код, е изключително важно да разберем архитектурните принципи. Често срещана грешка е опитът за анализи директно върху оперативни бази данни, което може да доведе до лоша производителност и неточни прозрения. Това е проблемът, който складовете за данни и OLAP са създадени да решат.
Какво е Склад за данни (DWH)?
Склад за данни е централизирано хранилище, което съхранява интегрирани данни от един или повече различни източника. Основната му цел е да поддържа дейностите по бизнес интелигентност (BI), особено анализи и отчети. Мислете за него като за единен източник на истина за историческите данни на една организация.
Той се различава рязко от база данни за онлайн обработка на транзакции (OLTP), която захранва ежедневните приложения (напр. система за плащане в електронна търговия или регистър на транзакции в банка). Ето бързо сравнение:
- Работно натоварване: OLTP системите обработват голям брой малки, бързи транзакции (четене, вмъкване, актуализиране). DWH са оптимизирани за по-малък брой сложни, дълготрайни заявки, които сканират милиони записи (предимно четене).
- Структура на данните: OLTP базите данни са силно нормализирани, за да се гарантира интегритет на данните и да се избегне излишък. DWH често са денормализирани, за да се опростят и ускорят аналитичните заявки.
- Цел: OLTP е за управление на бизнеса. DWH е за анализ на бизнеса.
Добре проектираният DWH се характеризира с четири ключови свойства, често приписвани на пионера Бил Инмън:
- Ориентиран към теми: Данните са организирани около основните теми на бизнеса, като 'Клиент', 'Продукт' или 'Продажби', а не около процеси на приложения.
- Интегриран: Данните се събират от различни източници и се интегрират в съгласуван формат. Например, 'САЩ', 'Съединени щати' и 'С. Щ.' могат всички да бъдат стандартизирани до едно записване 'Съединени щати'.
- Времево-вариращ: Данните в склада представляват информация за дълъг период от време (напр. 5-10 години), което позволява исторически анализ и идентифициране на тенденции.
- Неволатилен: След като данните бъдат заредени в склада, те рядко, ако изобщо някога, се актуализират или изтриват. Те стават постоянен запис на исторически събития.
Какво е OLAP (Онлайн Аналитична Обработка)?
Ако DWH е библиотеката с исторически данни, OLAP е мощната търсачка и аналитичен инструмент, който ви позволява да я изследвате. OLAP е категория софтуерни технологии, която позволява на потребителите бързо да анализират информация, която е обобщена в многоизмерни изгледи, известни като OLAP кубове.
OLAP кубът е концептуалното сърце на OLAP. Той не е непременно физическа структура от данни, а начин за моделиране и визуализиране на данни. Кубът се състои от:
- Мерки: Това са количествените, числени данни, които искате да анализирате, като 'Приходи', 'Продадено количество' или 'Печалба'.
- Измерения: Това са категорийни атрибути, които описват мерките, предоставяйки контекст. Чести измерения включват 'Време' (Година, Тримесечие, Месец), 'География' (Държава, Регион, Град) и 'Продукт' (Категория, Марка, SKU).
Представете си куб с данни за продажби. Можете да разглеждате общите приходи (мярката) по различни измерения. С OLAP можете да извършвате мощни операции върху този куб с невероятна скорост:
- Срез (Slice): Намаляване на многоизмерността на куба чрез избиране на една стойност за едно измерение. Пример: Разглеждане на данни за продажби само за 'Q4 2023'.
- Куб (Dice): Избиране на подкуб чрез специфициране на диапазон от стойности за множество измерения. Пример: Разглеждане на продажбите за 'Електроника' и 'Дрехи' (измерение Продукт) в 'Европа' и 'Азия' (измерение География).
- Проникване надолу / Проникване нагоре (Drill-Down / Drill-Up): Навигиране през нивата на детайлност в рамките на измерение. Проникване надолу преминава от обобщения на по-високо ниво към детайли на по-ниско ниво (напр. от 'Година' към 'Тримесечие' към 'Месец'). Проникване нагоре (или навиване нагоре) е обратното.
- Завъртане (Pivot): Въртене на осите на куба, за да получите нов изглед на данните. Пример: Размяна на осите 'Продукт' и 'География', за да видите кои региони купуват кои продукти, вместо кои продукти се продават в кои региони.
Типове OLAP системи
Съществуват три основни архитектурни модела за OLAP системи:
- MOLAP (Multidimensional OLAP): Това е "класическият" кубов модел. Данните се извличат от DWH и се предварително агрегират в собствена, многоизмерна база данни. Предимства: Изключително бърза производителност на заявките, тъй като всички отговори са предварително изчислени. Недостатъци: Може да доведе до "експлозия на данни", тъй като броят на предварително агрегираните клетки може да стане огромен, и може да бъде по-малко гъвкав, ако трябва да зададете въпрос, който не е бил предвиден.
- ROLAP (Relational OLAP): Този модел поддържа данните в релационна база данни (обикновено самия DWH) и използва усъвършенстван слой метаданни за превод на OLAP заявки в стандартен SQL. Предимства: Високо мащабируем, тъй като използва мощността на съвременните релационни бази данни и може да прави заявки към по-детайлни, данни в реално време. Недостатъци: Производителността на заявките може да бъде по-бавна от MOLAP, тъй като агрегациите се извършват в движение.
- HOLAP (Hybrid OLAP): Този подход се опитва да комбинира най-доброто от двата свята. Той съхранява агрегирани данни на високо ниво в MOLAP-подобен куб за скорост и поддържа детайлни данни в ROLAP релационната база данни за анализи с проникване надолу.
За съвременните стекове за данни, изградени с Python, границите са размити. С възхода на изключително бързи колонообразни бази данни, ROLAP моделът стана доминиращ и високоефективен, често осигурявайки производителност, съперничеща на традиционните MOLAP системи, без тяхната скованост.
Част 2: Екосистемата на Python за складиране на данни
Защо да изберем Python за задача, традиционно доминирана от корпоративни BI платформи? Отговорът се крие в неговата гъвкавост, мощна екосистема и способността му да обединява целия жизнен цикъл на данните.
Защо Python?
- Обединен език: Можете да използвате Python за извличане на данни (ETL), трансформация, зареждане, оркестрация, анализ, машинно обучение и разработка на API. Това намалява сложността и нуждата от превключване на контекста между различни езици и инструменти.
- Огромна екосистема от библиотеки: Python има зрели, доказани в битка библиотеки за всяка стъпка от процеса, от манипулация на данни (Pandas, Dask) до взаимодействие с бази данни (SQLAlchemy) и управление на работния процес (Airflow, Prefect).
- Независимост от доставчик: Python е с отворен код и се свързва с всичко. Независимо дали вашите данни се намират в PostgreSQL база данни, Snowflake склад, S3 хранилище за данни или Google Sheet, има Python библиотека, която да ви осигури достъп.
- Мащабируемост: Python решенията могат да се мащабират от обикновен скрипт, изпълняван на лаптоп, до разпределена система, обработваща петабайти данни в облачен клъстер, използвайки инструменти като Dask или Spark (чрез PySpark).
Основни Python библиотеки за стека за складиране на данни
Типично решение за складиране на данни, базирано на Python, не е единичен продукт, а подбрана колекция от мощни библиотеки. Ето основните:
За ETL/ELT (Извличане, Трансформация, Зареждане)
- Pandas: Стандартно решение за манипулация на данни в паметта в Python. Идеално за работа с малки до средни набори от данни (до няколко гигабайта). Неговият DataFrame обект е интуитивен и мощен за почистване, трансформиране и анализ на данни.
- Dask: Библиотека за паралелни изчисления, която мащабира вашите Python анализи. Dask предоставя паралелен DataFrame обект, който имитира Pandas API, но може да работи с набори от данни, по-големи от паметта, като ги разделя на части и ги обработва паралелно на множество ядра или машини.
- SQLAlchemy: Първокласен SQL инструмент и Object Relational Mapper (ORM) за Python. Той предоставя последователен, високо ниво API за свързване с почти всяка SQL база данни, от SQLite до складове на корпоративно ниво като BigQuery или Redshift.
- Оркестратори на работни процеси (Airflow, Prefect, Dagster): Склад за данни не се изгражда на един скрипт. Това е серия от зависими задачи (извличане от А, трансформация В, зареждане в С, проверка D). Оркестраторите ви позволяват да дефинирате тези работни процеси като насочени ациклични графи (DAGs), планирайки, наблюдавайки и повтаряйки ги с надеждност.
За съхранение и обработка на данни
- Конектори за облачни DWH: Библиотеки като
snowflake-connector-python,google-cloud-bigqueryиpsycopg2(за Redshift и PostgreSQL) позволяват безпроблемно взаимодействие с основни облачни складове за данни. - PyArrow: Ключова библиотека за работа с колонообразни формати на данни. Тя предоставя стандартизиран формат в паметта и позволява високоскоростен трансфер на данни между системи. Това е двигателят зад ефективното взаимодействие с формати като Parquet.
- Библиотеки за модерни Lakehouse: За напреднали настройки, библиотеки като
deltalake,py-icebergи - за потребители на Spark - родната поддръжка на PySpark за тези формати позволява на Python да изгражда надеждни, транзакционни езера от данни, които служат като основа на склада.
Част 3: Проектиране на OLAP система с Python
Сега, нека преминем от теория към практика. Ето стъпка по стъпка ръководство за проектиране на вашата аналитична система.
Стъпка 1: Моделиране на данни за анализи
Основата на всяка добра OLAP система е нейният модел на данни. Целта е да се структурират данните за бързо, интуитивно запитване. Най-често срещаните и ефективни модели са звездната схема и нейният вариант, снежната схема.
Звездна схема срещу Снежна схема
Звездната схема е най-широко използваната структура за складове за данни. Тя се състои от:
- Централна таблица с факти (Fact Table): Съдържа мерките (числата, които искате да анализирате) и външни ключове към таблиците с измерения.
- Няколко таблици с измерения (Dimension Tables): Всяка таблица с измерения е свързана с таблицата с факти чрез един ключ и съдържа описателни атрибути. Тези таблици са силно денормализирани за простота и скорост.
Пример: Таблица `FactSales` с колони като `DateKey`, `ProductKey`, `StoreKey`, `QuantitySold` и `TotalRevenue`. Тя ще бъде заобиколена от таблици `DimDate`, `DimProduct` и `DimStore`.
Снежната схема е разширение на звездната схема, при което таблиците с измерения са нормализирани в множество свързани таблици. Например, таблицата `DimProduct` може да бъде разделена на таблици `DimProduct`, `DimBrand` и `DimCategory`.
Препоръка: Започнете със Звездна схема. Заявките са по-прости (по-малко съединения), а съвременните колонообразни бази данни са толкова ефективни при работа с широки, денормализирани таблици, че ползите за съхранение на снежните схеми често са незначителни в сравнение с цената на производителността на допълнителни съединения.
Стъпка 2: Изграждане на ETL/ELT конвейера в Python
ETL процесът е гръбнакът, който захранва вашия склад за данни. Той включва извличане на данни от изходни системи, трансформирането им в чист и съгласуван формат и зареждането им във вашия аналитичен модел.
Нека илюстрираме с прост Python скрипт, използващ Pandas. Да приемем, че имаме изходен CSV файл с необработени поръчки.
# Опростен ETL пример, използващ Python и Pandas
import pandas as pd
# --- ИЗВЛИЧАНЕ ---
print("Извличане на необработени данни за поръчки...")
source_df = pd.read_csv('raw_orders.csv')
# --- ТРАНСФОРМАЦИЯ ---
print("Трансформиране на данни...")
# 1. Почистване на данни
source_df['order_date'] = pd.to_datetime(source_df['order_date'])
source_df['product_price'] = pd.to_numeric(source_df['product_price'], errors='coerce')
source_df.dropna(inplace=True)
# 2. Обогатяване на данни - Създаване на отделно измерение за дата
dim_date = pd.DataFrame({
'DateKey': source_df['order_date'].dt.strftime('%Y%m%d').astype(int),
'Date': source_df['order_date'].dt.date,
'Year': source_df['order_date'].dt.year,
'Quarter': source_df['order_date'].dt.quarter,
'Month': source_df['order_date'].dt.month,
'DayOfWeek': source_df['order_date'].dt.day_name()
}).drop_duplicates().reset_index(drop=True)
# 3. Създаване на продуктово измерение
dim_product = source_df[['product_id', 'product_name', 'category']].copy()
dim_product.rename(columns={'product_id': 'ProductKey'}, inplace=True)
dim_product.drop_duplicates(inplace=True).reset_index(drop=True)
# 4. Създаване на таблица с факти
fact_sales = source_df.merge(dim_date, left_on=source_df['order_date'].dt.date, right_on='Date')
.merge(dim_product, left_on='product_id', right_on='ProductKey')
fact_sales = fact_sales[['DateKey', 'ProductKey', 'order_id', 'quantity', 'product_price']]
fact_sales['TotalRevenue'] = fact_sales['quantity'] * fact_sales['product_price']
fact_sales.rename(columns={'order_id': 'OrderCount'}, inplace=True)
# Агрегиране до желаното ниво на детайлност
fact_sales = fact_sales.groupby(['DateKey', 'ProductKey']).agg(
TotalRevenue=('TotalRevenue', 'sum'),
TotalQuantity=('quantity', 'sum')
).reset_index()
# --- ЗАРЕЖДАНЕ ---
print("Зареждане на данни в целевото хранилище...")
# За този пример ще запазим в Parquet файлове, високоефективен колонообразен формат
dim_date.to_parquet('warehouse/dim_date.parquet')
dim_product.to_parquet('warehouse/dim_product.parquet')
fact_sales.to_parquet('warehouse/fact_sales.parquet')
print("ETL процесът завърши!")
Този прост скрипт демонстрира основната логика. В реално сценарио бихте опаковали тази логика във функции и бихте управлявали нейното изпълнение с оркестратор като Airflow.
Стъпка 3: Избор и внедряване на OLAP двигателя
С моделирани и заредени данни, се нуждаете от двигател, който да извършва OLAP операциите. В света на Python имате няколко мощни опции, предимно следващи ROLAP подхода.
Подход А: Леката мощна машина - DuckDB
DuckDB е вградена аналитична база данни, която е изключително бърза и лесна за използване с Python. Тя може да прави заявки към Pandas DataFrames или Parquet файлове директно, използвайки SQL. Тя е перфектният избор за OLAP системи с малък до среден мащаб, прототипи и локална разработка.
Тя действа като високопроизводителен ROLAP двигател. Пишете стандартен SQL, а DuckDB го изпълнява с екстремна скорост върху вашите файлове с данни.
import duckdb
# Свързване към база данни в паметта или към файл
con = duckdb.connect(database=':memory:', read_only=False)
# Директно правене на заявки към Parquet файловете, които създадохме по-рано
# DuckDB автоматично разбира схемата
result = con.execute("""
SELECT
p.category,
d.Year,
SUM(f.TotalRevenue) AS AnnualRevenue
FROM 'warehouse/fact_sales.parquet' AS f
JOIN 'warehouse/dim_product.parquet' AS p ON f.ProductKey = p.ProductKey
JOIN 'warehouse/dim_date.parquet' AS d ON f.DateKey = d.DateKey
WHERE p.category = 'Electronics'
GROUP BY p.category, d.Year
ORDER BY d.Year;
""").fetchdf() # fetchdf() връща Pandas DataFrame
print(result)
Подход Б: Облачните титани - Snowflake, BigQuery, Redshift
За мащабни корпоративни системи, облачен склад за данни е стандартен избор. Python се интегрира безпроблемно с тези платформи. Вашият ETL процес би заредил данни в облачния DWH, а вашето Python приложение (напр. BI табло или Jupyter тетрадка) би направило заявки към него.
Логиката остава същата като при DuckDB, но връзката и мащабът са различни.
import snowflake.connector
# Пример за свързване със Snowflake и изпълнение на заявка
conn = snowflake.connector.connect(
user='your_user',
password='your_password',
account='your_account_identifier'
)
cursor = conn.cursor()
try:
cursor.execute("USE WAREHOUSE MY_WH;")
cursor.execute("USE DATABASE MY_DB;")
cursor.execute("""
SELECT category, YEAR(date), SUM(total_revenue)
FROM fact_sales
JOIN dim_product ON ...
JOIN dim_date ON ...
GROUP BY 1, 2;
""")
# Извличане на резултати при нужда
for row in cursor:
print(row)
finally:
cursor.close()
conn.close()
Подход В: Специалистите за данни в реално време - Apache Druid или ClickHouse
За случаи на употреба, изискващи латентност на заявки под една секунда върху масивни, поточни данни (като анализи на потребители в реално време), специализирани бази данни като Druid или ClickHouse са отлични избори. Те са колонообразни бази данни, проектирани за OLAP работно натоварване. Python се използва за поточно предаване на данни към тях и за правене на заявки към тях чрез техните съответни клиентски библиотеки или HTTP API.
Част 4: Практически пример - Създаване на мини OLAP система
Нека комбинираме тези концепции в мини проект: интерактивно табло за продажби. Това демонстрира цялостна, макар и опростена, OLAP система, базирана на Python.
Нашият стек:
- ETL: Python и Pandas
- Съхранение на данни: Parquet файлове
- OLAP двигател: DuckDB
- Табло: Streamlit (библиотека с отворен код за Python за създаване на красиви, интерактивни уеб приложения за наука за данни)
Първо, стартирайте ETL скрипта от Част 3, за да генерирате Parquet файловете в директория `warehouse/`.
След това, създайте файла с приложението за табло, `app.py`:
# app.py - Опростено интерактивно табло за продажби
import streamlit as st
import duckdb
import pandas as pd
import plotly.express as px
# --- Конфигурация на страницата ---
st.set_page_config(layout="wide", page_title="Табло за глобални продажби")
st.title("Интерактивно OLAP табло за продажби")
# --- Свързване към DuckDB ---
# Това ще направи заявки към нашите Parquet файлове директно
con = duckdb.connect(database=':memory:', read_only=True)
# --- Зареждане на данни от измерения за филтри ---
@st.cache_data
def load_dimensions():
products = con.execute("SELECT DISTINCT category FROM 'warehouse/dim_product.parquet'").fetchdf()
years = con.execute("SELECT DISTINCT Year FROM 'warehouse/dim_date.parquet' ORDER BY Year").fetchdf()
return products['category'].tolist(), years['Year'].tolist()
categories, years = load_dimensions()
# --- Странична лента за филтри (Slicing и Dicing!)
st.sidebar.header("OLAP филтри")
selected_categories = st.sidebar.multiselect(
'Изберете продуктови категории',
options=categories,
default=categories
)
selected_year = st.sidebar.selectbox(
'Изберете година',
options=years,
index=len(years)-1 # По подразбиране последната година
)
# --- Динамично изграждане на OLAP заявката ---
if not selected_categories:
st.warning("Моля, изберете поне една категория.")
st.stop()
query = f"""
SELECT
d.Month,
d.MonthName, # Предполагаме, че MonthName съществува в DimDate
p.category,
SUM(f.TotalRevenue) AS Revenue
FROM 'warehouse/fact_sales.parquet' AS f
JOIN 'warehouse/dim_product.parquet' AS p ON f.ProductKey = p.ProductKey
JOIN 'warehouse/dim_date.parquet' AS d ON f.DateKey = d.DateKey
WHERE d.Year = {selected_year}
AND p.category IN ({str(selected_categories)[1:-1]})
GROUP BY d.Month, d.MonthName, p.category
ORDER BY d.Month;
"""
# --- Изпълнение на заявката и показване на резултатите ---
@st.cache_data
def run_query(_query):
return con.execute(_query).fetchdf()
results_df = run_query(query)
if results_df.empty:
st.info(f"Не са намерени данни за избраните филтри през {selected_year} г.")
else:
# --- Основни визуализации на таблото ---
col1, col2 = st.columns(2)
with col1:
st.subheader(f"Месечни приходи за {selected_year}")
fig = px.line(
results_df,
x='MonthName',
y='Revenue',
color='category',
title='Месечни приходи по категории'
)
st.plotly_chart(fig, use_container_width=True)
with col2:
st.subheader("Приходи по категории")
category_summary = results_df.groupby('category')['Revenue'].sum().reset_index()
fig_pie = px.pie(
category_summary,
names='category',
values='Revenue',
title='Дял на общите приходи по категории'
)
st.plotly_chart(fig_pie, use_container_width=True)
st.subheader("Детайлни данни")
st.dataframe(results_df)
За да стартирате това, запазете кода като `app.py` и изпълнете `streamlit run app.py` в терминала. Това ще стартира уеб браузър с вашето интерактивно табло. Филтрите в страничната лента позволяват на потребителите да извършват OLAP 'слайсинг' и 'дайсинг' операции, а таблото се актуализира в реално време, като прави повторни заявки към DuckDB.
Част 5: Напреднали теми и най-добри практики
Докато преминавате от мини проект към производствена система, помислете за тези напреднали теми.
Мащабируемост и производителност
- Използвайте Dask за големи ETL: Ако изходните ви данни надвишават RAM на вашата машина, заменете Pandas с Dask във вашите ETL скриптове. API е много сходен, но Dask ще се погрижи за обработка извън паметта и паралелна обработка.
- Колонообразното съхранение е ключово: Винаги съхранявайте данните на вашия склад в колонообразен формат като Apache Parquet или ORC. Това драстично ускорява аналитичните заявки, които обикновено се нуждаят само от четене на няколко колони от широка таблица.
- Партициониране: Когато съхранявате данни в хранилище за данни (като S3 или локална файлова система), партиционирайте данните си в папки въз основа на често филтрирано измерение, като дата. Например: `warehouse/fact_sales/year=2023/month=12/`. Това позволява на двигателите за заявки да пропускат четенето на нерелевантни данни, процес, известен като 'парционен таван'.
Семантичен слой
С нарастването на вашата система ще откриете, че бизнес логиката (като дефиницията на 'Активен потребител' или 'Брутна печалба') се повтаря в множество заявки и табла. Семантичен слой решава това, като предоставя централизирана, последователна дефиниция на вашите бизнес метрики и измерения. Инструменти като dbt (Data Build Tool) са изключителни за това. Въпреки че не е самостоятелен Python инструмент, dbt се интегрира перфектно в Python-оркестриран работен процес. Използвате dbt, за да моделирате вашата звездна схема и да дефинирате метрики, а след това Python може да бъде използван за оркестриране на dbt изпълнения и извършване на напреднал анализ върху получените чисти таблици.
Управление на данни и качество
Складът е толкова добър, колкото и данните в него. Интегрирайте проверки за качество на данните директно във вашите Python ETL конвейери. Библиотеки като Great Expectations ви позволяват да дефинирате 'очаквания' за вашите данни (напр. `customer_id` никога не трябва да бъде празен, `revenue` трябва да е между 0 и 1 000 000). Вашата ETL задача след това може да се провали или да ви предупреди, ако входящите данни нарушават тези договори, предотвратявайки лоши данни да повредят вашия склад.
Заключение: Силата на подхода, базиран на код
Python фундаментално промени пейзажа на складирането на данни и бизнес интелигентността. Той предоставя гъвкав, мощен и независим от доставчик набор от инструменти за изграждане на сложни аналитични системи от нулата. Чрез комбиниране на най-добрите в класа си библиотеки като Pandas, Dask, SQLAlchemy и DuckDB, можете да създадете цялостна OLAP система, която е едновременно мащабируема и поддържана.
Пътуването започва със солидно разбиране на принципите на моделиране на данни като звездната схема. Оттам можете да изградите стабилни ETL конвейери, за да оформите вашите данни, да изберете правилния двигател за заявки за вашия мащаб и дори да изградите интерактивни аналитични приложения. Този подход, базиран на код, често основен принцип на "Модерния стек за данни", поставя силата на анализите директно в ръцете на разработчиците и екипите за данни, като им позволява да изграждат системи, които са перфектно пригодени към нуждите на тяхната организация.